/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.core.persistence;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.exception.ErrorCodes;
import com.inspur.edp.lcm.metadata.api.exception.LcmMetadataDevException;
import com.inspur.edp.lcm.metadata.api.exception.LcmParseDevException;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.MetadataPropertyUtils;
import com.inspur.edp.lcm.metadata.common.MetadataSerializer;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.common.context.RuntimeContext;
import com.inspur.edp.lcm.metadata.core.MetadataProjectCoreService;
import com.inspur.edp.lcm.metadata.core.thread.BoGraphThreadLocalHolder;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.data.util.Pair;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
public class MetadataRepository {
    private final FileServiceImp fileService = new FileServiceImp();
    private final MetadataSerializer metadataSerializer=new MetadataSerializer();


    private final static Set<String> EXCLUDE_DIRS = new HashSet<>(Arrays.asList(".git", ".vs", "bin", "publish", "obj", "src", "java", "node_modules"));
    public GspMetadata load(String absolutePath) {
        var fileString = fileService.fileRead(absolutePath);
        var metadata = metadataSerializer.deserialize(fileString, GspMetadata.class);
        metadata.setRelativePath(absolutePath.substring(0, Utils.handlePath(absolutePath).lastIndexOf('/')));
        metadata.getHeader().setFileName(new File(absolutePath).getName());
        return metadata;
    }

    public GspMetadata getMetadataWithoutContent(String path) {
        return getMetadataWithoutContentAndContent(path).getSecond();
    }

    public Pair<JsonNode, GspMetadata> getMetadataWithoutContentAndContent(String path) {
        String fileStr = fileService.fileRead(path);
        if (fileStr == null || fileStr.isEmpty()) {
            throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0011, path);
        }
        ObjectMapper mapper = Utils.getMapper();
        JsonNode metadataObj ;
        JsonNode content;
        try {
            metadataObj = mapper.readTree(fileStr);
            content = metadataObj.findValue(MetadataPropertyUtils.content);
        } catch (JsonProcessingException e) {
            throw new LcmParseDevException(e, ErrorCodes.ECP_PARSE_DEV_0002, path);
        }
        GspMetadata metadata = metadataSerializer.buildMetadataBaseInfo(metadataObj);
        metadata.setRelativePath(path.substring(0, Utils.handlePath(path).lastIndexOf('/')));
        metadata.getHeader().setFileName(new File(path).getName());
        metadata.getHeader().setI18nName(RuntimeContext.getLanguage());
        return Pair.of(content, metadata);
    }

    public IMetadataContent deserializeMetadataContent(String metadataType, JsonNode contentJson) {
        return metadataSerializer.deserializeMetadataContent(metadataType, contentJson);
    }

    public void getMetadatasUnderDir(List<String> mdPathList, String dirPath) {
        List<File> dirs = fileService.getDirectorys(dirPath);
        if (dirs.size() > 0) {
            for (File dir : dirs) {
                String dirName = dir.getName();
                String temPath = Paths.get(dirPath, dirName).normalize().toString();

                if (!EXCLUDE_DIRS.contains(dirName.toLowerCase())) {
                    getMetadatasUnderDir(mdPathList, temPath);
                }
            }
        }
        List<File> paths = fileService.getAllFiles(dirPath);
        if (paths.size() > 0) {
            for (File path : paths) {
                mdPathList.add(Utils.handlePath(path.getPath()));
            }
        }
    }

    public void create(GspMetadata metadata, String path) {
        // 序列化元数据
        String metadataStr = metadataSerializer.serialize(metadata);
        String folderPath=new File(path).getParent();
        if(!fileService.isDirectoryExist(folderPath)){
            fileService.createDirectory(folderPath);
        }
        fileService.createFile(path);
        fileService.fileUpdate(path, metadataStr, false);
    }

    public void save(String path, String metadataStr) {
        FileServiceImp.createDirAndFile(path);
        fileService.fileUpdate(path, metadataStr, false);
        String projPath = MetadataProjectCoreService.getCurrent().getProjPath(path);
        BoGraphThreadLocalHolder.remove(projPath);
        // 更新最后修改人
//        Utils.setFileAttrLastChangedBy(path);
    }

    public void save(GspMetadata metadata, String path) {
        // 序列化元数据
        String metadataStr = metadataSerializer.serialize(metadata);
        fileService.fileUpdate(path, metadataStr, false);

        String projPath = MetadataProjectCoreService.getCurrent().getProjPath(path);
        BoGraphThreadLocalHolder.remove(projPath);
    }

    public void delete(String path) {
        try {
            fileService.fileDelete(path);
            String projPath = MetadataProjectCoreService.getCurrent().getProjPath(path);
            BoGraphThreadLocalHolder.remove(projPath);
        } catch (IOException e) {
            log.error("删除文件[{}]失败", path, e);
        }
    }

    public void rename(String oldName, String newName) {
        try {
            fileService.fileRename(oldName, newName);
        } catch (IOException e) {
            log.error("文件[{}]重命名为[{}]失败", oldName, newName, e);
        }
    }
}
